package com.my.db.test.mybatis;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;

/**
 * mybatis拦截器，自动注入创建人、创建时间、修改人、修改时间
 * @Date  2019-01-19
 */
@Slf4j
@Component
//@Intercepts 在实现Interceptor接口的类声明,使该类注册成为拦截器
//Signature[] value //定义需要拦截哪些类的哪些方法
//Class<?> type() //ParameterHandler,ResultSetHandler,StatementHandler,Executor
//		String method()
//		Class<?>[] args()
@Intercepts({
		@Signature(
				type = Executor.class, method = "update", args = {
						MappedStatement.class, Object.class
				}
		)
})
public class MybatisInterceptor implements Interceptor {

	public static String createBy = "createUser";
	public static String createTime = "createTime";
	public static String updateBy = "updateUser";
	public static String updateTime = "updateTime";

	//是实现拦截逻辑的地方，内部要通过invocation.proceed()显式地推进责任链前进，也就是调用下一个拦截器拦截目标方法。
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
		SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
		log.debug("------sqlCommandType------" + sqlCommandType);
		String sqlId = mappedStatement.getId();
		log.debug("------sqlId------" + sqlId);
		Object parameter = invocation.getArgs()[1];
//		https://blog.csdn.net/caideb/article/details/81480260
//		BoundSql boundSql = mappedStatement.getBoundSql(parameter);
//		String oldsql = boundSql.getSql();
//		log.info("old:"+oldsql);
		// 改变sql语句
//		BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), oldsql + " where id=1",
//				boundSql.getParameterMappings(), boundSql.getParameterObject());
//		MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));
//		invocation.getArgs()[0] = newMs;


		if (parameter == null) {
			// 继续执行
			return invocation.proceed();
		}
		if (SqlCommandType.INSERT == sqlCommandType) {
//			LoginUser sysUser = this.getLoginUser();
			Field[] fields = getAllFields(parameter);
			for (Field field : fields) {
				log.debug("------field.name------" + field.getName());
				try {
					if (MybatisInterceptor.createBy.equals(field.getName())) {
						field.setAccessible(true);
						Object local_createBy = field.get(parameter);
						field.setAccessible(false);
						if (local_createBy == null || local_createBy.equals("")) {
//							if (sysUser != null) {
								// 登录人账号
								field.setAccessible(true);
								field.set(parameter, "updateAdmin");
								field.setAccessible(false);
//							}
						}
					}
					// 注入创建时间
					if (MybatisInterceptor.createTime.equals(field.getName())) {
						field.setAccessible(true);
						Object local_createDate = field.get(parameter);
						field.setAccessible(false);
						if (local_createDate == null || local_createDate.equals("")) {
							field.setAccessible(true);
							field.set(parameter, new Date());
							field.setAccessible(false);
						}
					}
					//注入部门编码
//					if ("sysOrgCode".equals(field.getName())) {
//						field.setAccessible(true);
//						Object local_sysOrgCode = field.get(parameter);
//						field.setAccessible(false);
//						if (local_sysOrgCode == null || local_sysOrgCode.equals("")) {
//							// 获取登录用户信息
//							if (sysUser != null) {
//								field.setAccessible(true);
//								field.set(parameter, sysUser.getOrgCode());
//								field.setAccessible(false);
//							}
//						}
//					}
				} catch (Exception e) {
				}
			}
		}
		if (SqlCommandType.UPDATE == sqlCommandType) {
//			LoginUser sysUser = this.getLoginUser();
			Field[] fields = null;
			if (parameter instanceof ParamMap) {
				ParamMap<?> p = (ParamMap<?>) parameter;
				//update-begin-author:scott date:20190729 for:批量更新报错issues/IZA3Q--
				if (p.containsKey("et")) {
					parameter = p.get("et");
				} else {
					parameter = p.get("param1");
				}
				//update-end-author:scott date:20190729 for:批量更新报错issues/IZA3Q-

				//update-begin-author:scott date:20190729 for:更新指定字段时报错 issues/#516-
				if (parameter == null) {
					return invocation.proceed();
				}
				//update-end-author:scott date:20190729 for:更新指定字段时报错 issues/#516-

				fields = getAllFields(parameter);
			} else {
				fields = getAllFields(parameter);
			}

			for (Field field : fields) {
				log.debug("------field.name------" + field.getName());
				try {
					if (MybatisInterceptor.updateBy.equals(field.getName())) {
						//获取登录用户信息
//						if (sysUser != null) {
							// 登录账号
							field.setAccessible(true);
							field.set(parameter, "updateAdmin");
							field.setAccessible(false);
//						}
					}
					if (MybatisInterceptor.updateTime.equals(field.getName())) {
						field.setAccessible(true);
						field.set(parameter, new Date());
						field.setAccessible(false);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return invocation.proceed();
	}
	//就是用当前这个拦截器生成对目标target的代理，实际是通过Plugin.wrap(target,this) 来完成的，把目标target和拦截器this传给了包装函数。
	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}
	//用于设置额外的参数，参数配置在拦截器的Properties节点里。
	@Override
	public void setProperties(Properties properties) {
		// TODO Auto-generated method stub
	}

//	private LoginUser getLoginUser() {
//		LoginUser sysUser = null;
//		try {
//			sysUser = SecurityUtils.getSubject().getPrincipal() != null ? (LoginUser) SecurityUtils.getSubject().getPrincipal() : null;
//		} catch (Exception e) {
//			//e.printStackTrace();
//			sysUser = null;
//		}
//		return sysUser;
//	}

    /**
     * 获取类的所有属性，包括父类
     * @param object
     * @return
     */
    public static Field[] getAllFields(Object object) {
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }


	// 复制原始MappedStatement
//	private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
//		MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource,
//				ms.getSqlCommandType());
//		builder.resource(ms.getResource());
//		builder.fetchSize(ms.getFetchSize());
//		builder.statementType(ms.getStatementType());
//		builder.keyGenerator(ms.getKeyGenerator());
//		if (ms.getKeyProperties() != null) {
//			for (String keyProperty : ms.getKeyProperties()) {
//				builder.keyProperty(keyProperty);
//			}
//		}
//		builder.timeout(ms.getTimeout());
//		builder.parameterMap(ms.getParameterMap());
//		builder.resultMaps(ms.getResultMaps());
//		builder.cache(ms.getCache());
//		builder.useCache(ms.isUseCache());
//		return builder.build();
//	}
//
//	public static class BoundSqlSqlSource implements SqlSource {
//		BoundSql boundSql;
//
//		public BoundSqlSqlSource(BoundSql boundSql) {
//			this.boundSql = boundSql;
//		}
//
//		public BoundSql getBoundSql(Object parameterObject) {
//			return boundSql;
//		}
//	}

}
